/*global $ jQuery window LOCK5MAIN */

$( function() {
    // global objects
    LOCK5MAIN.histogramTypes = ["proportion", "count"];
    LOCK5MAIN.histograms = {};
    $.each(LOCK5MAIN.histogramTypes, function(i, type) {
        LOCK5MAIN.histograms[type] = $.createHistogram({
            raggedPlot: true
        });
        LOCK5MAIN.histograms[type].type = type;
    });
    LOCK5MAIN.activeHistogram = LOCK5MAIN.histograms.proportion;
    LOCK5MAIN.hypothesisTest = true;

    LOCK5MAIN.editDataDialog = ( function() {

        var clearErrors, addErrorMessage, dataEditor = $('<div><p>Please select values for count and n.</p><table><tr><td><label for="count">count:</label></td><td><input type="text" name="count" id="count" value="" /></td></tr><tr><td><label for="n">n:</label></td><td><input type="text" name="n" id="n" value="" /></td></tr></table><\/div>');
        clearErrors = function(dialog) {
            $(".errorMessage",dialog).remove();
            $('.ui-state-error',dialog).removeClass('ui-state-error');
        };
        addErrorMessage = function(id,message) {
            $(id,dataEditor).addClass('ui-state-error');
            $(id,dataEditor).parent().after("<td><p class='errorMessage ui-state-error-text'>"+message+"</p></td>");
        };
        dataEditor.appendTo('body');
        $(dataEditor).dialog({
            autoOpen: false,
            modal: true,
            open: function() {
                clearErrors(dataEditor);
            },
            buttons: [{
                text: "Ok",
                click: function () {
                    var count, n, valid, integerRe = /^-?\d\d*$/;
                    clearErrors(dataEditor);
                    count = $("#count",dataEditor).val();
                    n = $("#n",dataEditor).val();
                    valid = true;

                    if (integerRe.test(n)) {
                        n = parseInt(n,10);
                        if (n <= 0) {
                            addErrorMessage("#n","Enter positive integers");
                            valid = false;
                        }
                    } else {
                        valid = false;
                        addErrorMessage("#n","Enter integers only");
                    }

                    if (integerRe.test(count)) {
                        count = parseInt(count,10);
                        if (count < 0) {
                            addErrorMessage("#count","Enter positive integers");
                            valid = false;
                        } else if (valid && count > n) {
                            addErrorMessage("#count","Enter count that is less than n");
                            valid = false;
                        }
                    } else {
                        valid = false;
                        addErrorMessage("#count","Enter integers only");
                    }

                    if (valid) {
                        $("#data-source-button").button({
                            label:"Custom Data"
                        });
                        LOCK5MAIN.initialize({
                            count: count,
                            n: n,
                            label: "Custom Dataset"
                        });
                        LOCK5MAIN.updateNullHypothesisControl();
                        dataEditor.dialog("close");
                    }
                }
            }],
            title: "Edit data"
        }).attr("id", "dataeditordialog");

        $("button#edit-data-source-button").button().click( function() {
            dataEditor.dialog("open");
        });
        return dataEditor;
    }());
    /* Methods */

    /*
     * LOCK5MAIN.clearGraph Clears everything to do with the LOCK5MAIN
     * randomization graph including data and control settings.
     *
     * Returns true
     */
    LOCK5MAIN.clearGraph = function() {
        // bootstrap some initial points to determine the initial xaxis
        // bounds on graph
        var bootstrapGraphWidth, samplePoints;
        samplePoints = LOCK5MAIN.generateNRandomizationSamples(LOCK5MAIN.ORIGINAL_SAMPLE, 1000);
        // set up ranges on each histogram
        $.each(LOCK5MAIN.histograms, function(type, h) {
            ( function(array) {
                h.max = $.selection(array, 0);
                h.min = $.selection(array, array.length - 1);
            }($.map(samplePoints, function(sample) {
                return sample[type];
            })));
        });
        LOCK5MAIN.dotPlot.setBounds({
            xaxis: {
                //histogram sorts points backwards
                min: LOCK5MAIN.activeHistogram.max,
                max: LOCK5MAIN.activeHistogram.min
            },
            yaxis: {
                min: 0,
                max: Math.floor(parseInt($("#dotplot").height(), 10) / LOCK5MAIN.PIXELSPERDOT)
            }
        });

        bootstrapGraphWidth = parseInt($("#dotplot").width(), 10);
        $.each(LOCK5MAIN.histograms, function(key, histogram) {
            histogram.k = Math.floor(bootstrapGraphWidth / LOCK5MAIN.PIXELSPERDOT);
        });
        $.each(LOCK5MAIN.histograms, function(i, h) {
            h.clear();
        });
        LOCK5MAIN.dotPlot.clear();
        $("#current-sample-table").empty();
        return true;
    };
    /*
     * hoverGraph: Function that is called when the mouse hovers over a
     * point on the dotplot
     *
     * parameters: id (String) the css id of the element to plot over
     */
    LOCK5MAIN.hoverGraph = function(id) {
        return function(event, pos, item) {
            if (item) {
                var generatedFrom = item.series.data[item.dataIndex][2];
                LOCK5MAIN.makeTable("#current-sample-table", generatedFrom);
            }
        };
    };
    /*
     * LOCK5MAIN.generateNRandomizationSamples: generates statistics from the given
     * points
     *
     * returns: Array of statistics. A statistic is an object containing
     * statistics for each input function
     *
     * parameters: dataset (Object): describes the n and count of original sample,
     * n (Integer): the number of samples to generate
     */
    LOCK5MAIN.generateNRandomizationSamples = function(dataset, n) {
        var sampleNumber, nullProportion, tmpCount, pointNumber, statistics = [];
        // generate n boostrap samples
        if (LOCK5MAIN.activeHistogram.type === 'proportion') {
            //if its a proportion, use it directly
            nullProportion = LOCK5MAIN.activeHistogram.nullHypothesis;
        } else if (LOCK5MAIN.activeHistogram.type === 'count') {
            //if it's a count, use that to get the proportion
            nullProportion = LOCK5MAIN.activeHistogram.nullHypothesis/LOCK5MAIN.ORIGINAL_SAMPLE.n;
        } else {
            console.err("Unknown histogram type " + LOCK5MAIN.activeHistogram.type);
        }
        for (sampleNumber = 0; sampleNumber < n; sampleNumber += 1) {
            // generate count random samples
            tmpCount = 0;
            for (pointNumber = 0; pointNumber < dataset.n; pointNumber += 1) {
                // random sample an index
                if (Math.random() <= nullProportion) {
                    tmpCount += 1;
                }
            }
            statistics.push({
                count: tmpCount,
                proportion: tmpCount / dataset.n,
                generatedFrom: {
                    count: tmpCount,
                    n: dataset.n
                }
            });
        }
        return statistics;
    };
    /*
     * generateAndPlotRandomizationSample: helper function to generate n additional
     * points and plot the current total.
     *
     * returns: true
     *
     * parameters: point (Array): the original data to sample n (Integer):
     * nubmer of points to generate slopeFunction (function): calculates the
     * slope statistic from the boostrap points correlationFunction (function):
     * calculates the correlation statistic from the boostrap points
     */
    LOCK5MAIN.generateAndPlotRandomizationSample = function(n) { //
        return function() {

            // calculate samples
            var statistics = LOCK5MAIN.generateNRandomizationSamples(LOCK5MAIN.ORIGINAL_SAMPLE, n);

            // add those samples to each histogram
            $.each(LOCK5MAIN.histograms, function(i, h) {
                h.addPoints(statistics);
            });
            // plot the Randomization plot with the old and new samples from
            // the current active histogram
            LOCK5MAIN.dotPlot.plot("#dotplot", LOCK5MAIN.activeHistogram.histogramPoints);

            LOCK5MAIN.makeTable("#current-sample-table", statistics[0].generatedFrom);
            return true;
        };
    };
    /**
     * LOCK5MAIN.setupRandomizationMenu: defines dropdown box for the kinds of
     * dotplots the application can handle.  Only effective to call once, otherwise
     * does nothing.
     */
    $( function setupRandomizationMenu() {
        var highlight, callback;
        callback = function(histogram) {
            return function() {
                LOCK5MAIN.activeHistogram = histogram;
                LOCK5MAIN.dotPlot.setBounds({
                    xaxis: {
                        //histogram sorts points backwards
                        min: LOCK5MAIN.activeHistogram.max,
                        max: LOCK5MAIN.activeHistogram.min
                    },
                    yaxis: {
                        min: 0,
                        max: Math.floor(parseInt($("#dotplot").height(), 10) / LOCK5MAIN.PIXELSPERDOT)
                    }
                });
                LOCK5MAIN.updateNullHypothesisControl();
                LOCK5MAIN.dotPlot.plot("#dotplot", LOCK5MAIN.activeHistogram.histogramPoints, LOCK5MAIN.activeHistogram.graphProperties);
                highlight();
            };
        };
        highlight = function() {
            $("#dotplot").effect("highlight", {
                color: "#eee"
            }, 350);
        };
        $.createPopupMenu($("#bootstrap-type-button"), [{
            label: "Proportion",
            callback: callback(LOCK5MAIN.histograms.proportion)
        },{
            label: "Count",
            callback: callback(LOCK5MAIN.histograms.count)
        }]);
        LOCK5MAIN.updateNullHypothesisControl();
    });
    /*
     * LOCK5MAIN.initialize(dataset) Initializes both plots based on
     * the 1D dataset of count and n passed to it.
     *
     * returns None
     *
     * Parameters dataset (Object): contains a count and n varaible representing a 1D quantitative variable
     */
    LOCK5MAIN.initialize = function(dataset) {
        LOCK5MAIN.ORIGINAL_SAMPLE.n = dataset.n;
        LOCK5MAIN.ORIGINAL_SAMPLE.count = dataset.count;

        //The default porportion on the null hypothesis is always 0.5; it's a stats thing?
        LOCK5MAIN.histograms.proportion.nullHypothesis = 0.5;
        LOCK5MAIN.histograms.count.nullHypothesis = Math.truncate(dataset.n*LOCK5MAIN.histograms.proportion.nullHypothesis,0);

        LOCK5MAIN.makeTable("#original-sample-table", LOCK5MAIN.ORIGINAL_SAMPLE);

        // LOCK5MAIN.PIXELSPERDOT and physical width of graph determine
        // histogram buckets
        LOCK5MAIN.clearGraph();
    };
    /** nullHypothesisDialog: creates the null hypothesis dialog box that's used to change
     * the null hypothesis
     */
    $( function nullHypothesisDialog() {
        var nullHypothesisForm = $('<div id="null-hypothesis-form"><p class="validateTips">Enter the null hypothesis as a decimal between 0.0 and 1.0.<\/p><form><label for="null-hypothesis-input">Null Hypothesis<\/label><input type="text" name="null-hypothesis-input" id="null-hypothesis-input" class="text ui-widget-content ui-corner-all"\/><\/form><\/div>'),
        callback = function(dialog) {
            return function() {
                var nullHypothesis, valid;
                nullHypothesis = parseFloat($("#null-hypothesis-input", dialog).val());
                valid = !isNaN(nullHypothesis) && nullHypothesis >=0 && nullHypothesis <= 1.0;
                // validate
                if (!valid) {
                    $("#cutoff", dialog).addClass("ui-state-error");
                    $(".validateTips", dialog).addClass("ui-state-highlight");
                } else {
                    LOCK5MAIN.histograms.proportion.nullHypothesis = nullHypothesis;
                    LOCK5MAIN.histograms.count.nullHypothesis = nullHypothesis*LOCK5MAIN.ORIGINAL_SAMPLE.n;
                    dialog.dialog("close");
                    LOCK5MAIN.updateNullHypothesisControl();
                    LOCK5MAIN.clearGraph();
                }
                return false;
            };
        };
        nullHypothesisForm.dialog({
            autoOpen: false,
            title: "Define Null Hypothesis",
            modal: true,
            show: {
                effect: "fade",
                speed: "fast"
            },
            hide: {
                effect: "fade",
                speed: "fast"
            },
            buttons: [{
                text: "Ok (or hit Enter)",
                click: callback(nullHypothesisForm)
            }]
        });
        nullHypothesisForm.submit(callback(nullHypothesisForm));
    });
    /**
     * updateHypothesisCallback: funciton used when the null hypothesis needs
     * to be updated
     */
    LOCK5MAIN.updateHypothesisCallback = ( function() {
        return function() {
            $("#null-hypothesis-form").dialog("open");
        };
    }());
    /**
     * updateNullHypothesisControl: this function serves as a central point to
     * update the null hypothesis control on the main application
     */
    LOCK5MAIN.updateNullHypothesisControl = function() {
        //Display the message and provide the callback.
        $("#null-hypothesis").html("<em>$p = $"+"<button id='null-hypothesis-button'><\/button><\/em>");
        MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
        $("#null-hypothesis-button").button({
            label: LOCK5MAIN.histograms.proportion.nullHypothesis
        }).click(LOCK5MAIN.updateHypothesisCallback);
    };
    /* Initialize the application */
    $( function() {
        LOCK5MAIN.startup({
            sampleType: "Randomization",
            generateAndPlot: LOCK5MAIN.generateAndPlotRandomizationSample,
            graphAnnotation: function(arrowAnnotationFn, plot, xyList) {
                var text = "null = " + Math.truncate(LOCK5MAIN.activeHistogram.nullHypothesis, 3);
                arrowAnnotationFn(plot, LOCK5MAIN.activeHistogram.nullHypothesis, text, "#000");
            },
            onLoad: function () {
                LOCK5MAIN.updateNullHypothesisControl();
            },
            parseCSV: false
        });
    });
});